package com.rz.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rz.admin.entity.Admin;
import com.rz.admin.entity.AdminRole;
import com.rz.admin.entity.Res;
import com.rz.admin.entity.UserToken;
import com.rz.admin.entity.vo.DeleteParam;
import com.rz.admin.mapper.AdminMapper;
import com.rz.admin.mapper.AdminRoleMapper;
import com.rz.admin.service.*;
import com.rz.core.config.RedisKeys;
import com.rz.core.exception.GlobalException;
import com.rz.core.kit.PwdKit;
import com.rz.core.kit.RedisKit;
import com.rz.core.resp.RespEnum;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class AdminService extends ServiceImpl<AdminMapper, Admin> implements IAdminService {

    @Resource
    private IRoleResService roleResService;
    @Resource
    private IResService resService;
    @Resource
    private AdminRoleMapper adminRoleMapper;
    @Resource
    private IAdminRoleService adminRoleService;
    @Resource
    private IGroupResService groupResService;
    @Resource
    private IUserTokenService userTokenService;
    @Resource
    private RedisKit redisKit;

    @Override
    public Map<String, Object> login(Admin admin) {
        Admin adminLogin = getByUsername(admin.getUsername());
        if (adminLogin == null) {
            throw new GlobalException(RespEnum.USERNAME_ERROR);
        }
        String adminPwd = PwdKit.getRealPwd(admin.getPassword(), adminLogin.getRdmSalt());
        if (!adminPwd.equals(adminLogin.getPassword())) {
            throw new GlobalException(RespEnum.USERNAME_PWD_ERROR);
        }
        List<Res> resList = roleResService.getResByAdminId(adminLogin.getId(),true);
        List<Res> groupRes = new ArrayList<>(groupResService.getResByGroupId(Collections.singletonList(adminLogin.getGroupId())));
        List<Res> all = new ArrayList<>();
        all.addAll(resList);
        all.addAll(groupRes);
        ArrayList<Res> distinctByIdList = all.stream()
                .collect(
                    Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Res::getId))),
                        ArrayList::new
                    )
                );
        List<Res> resTreeList = resService.buildResTree(distinctByIdList);
        Map<String, Object> map = new HashMap<>();
        Object token = redisKit.getValue("userkey_"+adminLogin.getId().toString());
        if(token!=null){
            adminLogin.setUserToken(token.toString());
        }
        map.put("admin", adminLogin);
        map.put("resList", distinctByIdList);
        map.put("resTreeList", resTreeList);
        return map;
    }

    @Override
    public Admin getByUsername(String username) {
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        return getOne(queryWrapper);
    }

    @Override
    public IPage<Admin> getPage(Admin admin) {
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        List<Integer> mngID = getChildrenIds(admin.getCrteAdminId());
        mngID.add(admin.getCrteAdminId());
        queryWrapper.in("crte_admin_id",mngID);
        Page<Admin> page = new Page<>(admin.getPageNo(), admin.getPageSize());
        return page(page, queryWrapper);
    }

    @Override
    @Transactional
    public boolean batchDelete(DeleteParam deleteParam) {
        deleteParam.getIds().forEach(adminId->{
            adminRoleMapper.deleteByAdminId(adminId);
        });
        return removeByIds(deleteParam.getIds());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean onSave(Admin admin) {
        if (admin.getId() == null) {
            admin.setCrteTime(LocalDateTime.now());
            if(isRepeat(admin.getUsername(),admin.getOrgId())){
                throw new GlobalException("账号已存在，请重新输入");
            }
            String salt = PwdKit.getSlat();
            String password = PwdKit.getRealPwd(admin.getPassword(),salt);
            admin.setRdmSalt(salt);
            admin.setPassword(password);
        }else{
            Admin oldAdmin = getById(admin.getId());
            List<Admin> admins = getByUserNameAndOrgId(admin.getUsername(),admin.getOrgId());
            if(admins.size()>0){
                if(oldAdmin!=null && !oldAdmin.getUsername().equals(admin.getUsername())
                        && oldAdmin.getOrgId().equals(admin.getOrgId())){
                    throw new GlobalException("账号已存在，请重新输入");
                }
            }
        }
        boolean saveAdmin = saveOrUpdate(admin);
        if(saveAdmin){
            UserToken userToken = new UserToken();
            userToken.setUserKey(admin.getId().toString());
            String token = PwdKit.getToken();
            userToken.setUserToken(token);
            userTokenService.save(userToken);
            redisKit.setValue("userkey_"+admin.getId().toString(),token,0);
        }
        adminRoleMapper.deleteByAdminId(admin.getId());
        if (admin.getRoleIds() != null && admin.getRoleIds().size() > 0) {
            List<AdminRole> adminRoles = new ArrayList<>();
            admin.getRoleIds().forEach(roleId -> adminRoles.add(new AdminRole(admin.getId(), roleId)));
            adminRoleService.saveBatch(adminRoles);
        }

        return saveAdmin;
    }

    @Override
    public List<Admin> getByUserNameAndOrgId(String username, Integer orgId) {
        QueryWrapper<Admin> adminQueryWrapper = new QueryWrapper<>();
        adminQueryWrapper.eq("username",username);
        adminQueryWrapper.eq("org_id",orgId);
        return list(adminQueryWrapper);
    }

    @Override
    public boolean isRepeat(String username, Integer orgId) {
        List<Admin> admins = getByUserNameAndOrgId(username,orgId);
        return admins!=null && admins.size()>0;
    }

    /**
     * 获取指定类型的系统用户
     * @param type
     * @return
     */
    public List<Admin> getAdminByType(Integer type){
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type", type);
        return list(queryWrapper);
    }

    /**
     * 获取指定用户的子孙级用户列表（不包含自身）
     * @param id
     * @return
     */
    public void getChildren(Integer id,List<Integer> result){
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("crte_admin_id", id);
        List<Admin> list = list(queryWrapper);
        if (list!=null && list.size() > 0) {
            for (Admin admin : list) {
                result.add(admin.getId());
                getChildren(admin.getId(),result);
            }
        }
    }

    public void getChildrenAdmin(Integer id,List<Admin> result){
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("crte_admin_id", id);
        List<Admin> list = list(queryWrapper);
        if (list!=null && list.size() > 0) {
            for (Admin admin : list) {
                result.add(admin);
                getChildrenAdmin(admin.getId(),result);
            }
        }
    }

    /**
     * 获取指定用户的子孙级用户id列表（不包含自身id）
     * @param id
     * @return
     */
    public List<Integer> getChildrenIds(Integer id){
        List<Integer> result = new ArrayList<>();
        getChildren(id,result);
        return result;
    }

    @Override
    public boolean updatePwd(Admin admin) {
        Admin oldAdmin = getById(admin.getId());
        String oldPwd = PwdKit.getRealPwd(admin.getOldPwd(),oldAdmin.getRdmSalt());
        if(!oldPwd.equals(oldAdmin.getPassword())){
            throw new GlobalException("旧密码不正确");
        }
        if(!admin.getPassword().equals(admin.getSurePwd())){
            throw new GlobalException("两次输入新密码不一致");
        }
        if(admin.getPassword().length() <= 6){
            throw new GlobalException("密码长度必须大于6");
        }
        String rdmSalt= PwdKit.getSlat();
        String realPwd = PwdKit.getRealPwd(admin.getPassword(),rdmSalt);
        oldAdmin.setPassword(realPwd);
        oldAdmin.setRdmSalt(rdmSalt);
        return saveOrUpdate(oldAdmin);
    }
}
